/**
 * 通用js方法封装处理
 * Copyright (c) 2019
 * peng zhang
 */

import request from "@/utils/request";

// 日期格式化
function parseTime(time: string | number | Date, pattern: string) {
  // if (arguments.length === 0 || !time) {
  if (!time) {
    return null;
  }
  const format = pattern || "{y}-{m}-{d} {h}:{i}:{s}";
  let date: Date;
  if (typeof time === "object") {
    date = time;
  } else {
    if (typeof time === "string" && /^[0-9]+$/.test(time)) {
      time = parseInt(time);
    } else if (typeof time === "string") {
      // eslint-disable-next-line prefer-regex-literals
      time = time
        .replace(new RegExp(/-/gm), "/")
        .replace("T", " ")
        .replace(new RegExp(/\.[\d]{3}/gm), "");
    }
    if (typeof time === "number" && time.toString().length === 10) {
      time = time * 1000;
    }
    date = new Date(time);
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay(),
  };
  return format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key];
    // // Note: getDay() returns 0 on Sunday
    // if (key === "a") {
    //   return ["日", "一", "二", "三", "四", "五", "六"][value];
    // }
    if (result.length > 0 && value < 10) {
      value = "0" + value;
    }
    return value || 0;
  });
}

/**
 * 获取当前日期对应的星期
 * @param time 当前日期时间
 */
function getWeek(time: Date): string {
  let cerrentWeek = "";
  let week = new Date(time).getDay();
  let weeks = ["日", "一", "二", "三", "四", "五", "六"];
  return (cerrentWeek = "星期" + weeks[week]);
}

/**
 * 参数处理
 * @param {*} params  参数
 */
function tansParams(params) {
  let result = "";
  for (const propName of Object.keys(params)) {
    const value = params[propName];
    const part = encodeURIComponent(propName) + "=";
    if (value !== null && value !== "" && typeof value !== "undefined") {
      if (typeof value === "object") {
        for (const key of Object.keys(value)) {
          if (
            value[key] !== null &&
            value[key] !== "" &&
            typeof value[key] !== "undefined"
          ) {
            const params = propName + "[" + key + "]";
            const subPart = encodeURIComponent(params) + "=";
            result +=
              subPart + encodeURIComponent(value[key]) + "&";
          }
        }
      } else {
        result += part + encodeURIComponent(value) + "&";
      }
    }
  }
  return result;
}

// 验证是否为blob格式
async function blobValidate(data) {
  try {
    const text = await data.text();
    JSON.parse(text);
    return false;
  } catch (error) {
    return true;
  }
}

// 转换字符串，undefined,null等转化为""
function parseStrEmpty(str: string) {
  if (!str || str == "undefined" || str == "null") {
    return "";
  }
  return str;
}

// 表单重置
function resetForm(formEl) {
  if (!formEl) return;
  formEl.resetFields();
}

/**
 * 构造树型结构数据
 * @param {*} data 数据源
 * @param {*} id id字段 默认 'id'
 * @label {*} label 需要显示的名字 默认 'label'
 * @param {*} parentId 父节点字段 默认 'parentId'
 * @param {*} children 孩子节点字段 默认 'children'
 */
function handleTree(data, id, label, parentId, children): any[] {
  let config = {
    id: id || "id",
    parentId: parentId || "parentId",
    childrenList: children || "children",
  };

  let childrenListMap = {};
  let nodeIds = {};
  let tree: any[] = [];

  for (let d of data) {
    d.label = d[label];
    d.value = d[id];
    let parentId = d[config.parentId];
    if (childrenListMap[parentId] == null) {
      childrenListMap[parentId] = [];
    }
    nodeIds[d[config.id]] = d;
    childrenListMap[parentId].push(d);
  }

  for (let d of data) {
    d.label = d[label];
    d.value = d[id];
    let parentId = d[config.parentId];
    if (nodeIds[parentId] == null) {
      tree.push(d);
    }
  }

  for (let t of tree) {
    adaptToChildrenList(t);
  }

  function adaptToChildrenList(o) {
    if (childrenListMap[o[config.id]] !== null) {
      o[config.childrenList] = childrenListMap[o[config.id]];
    }
    if (o[config.childrenList]) {
      for (let c of o[config.childrenList]) {
        adaptToChildrenList(c);
      }
    }
  }

  return tree;
}

// 返回项目路径
function getNormalPath(p) {
  if (p.length === 0 || !p || p == "undefined") {
    return p;
  }
  let res = p.replace("//", "/");
  if (res[res.length - 1] === "/") {
    return res.slice(0, res.length - 1);
  }
  return res;
}

// 添加日期范围
function addDateRange(params, dateRange, propName) {
  let search = params;
  search.params =
    typeof search.params === "object" &&
    search.params !== null &&
    !Array.isArray(search.params)
      ? search.params
      : {};
  dateRange = Array.isArray(dateRange) ? dateRange : [];

  if (typeof propName === "undefined") {
    search.params["beginTime"] = dateRange[0];
    search.params["endTime"] = dateRange[1];
  } else {
    search.params[propName + "Begin"] = dateRange[0];
    search.params[propName + "End"] = dateRange[1];
  }
  return search;
}

/**
 * 根据身份证获取性别
 * @param form
 */
function certificateNoInSex(idCard: any) {
  // 身份证
  if (idCard) {
    if (idCard.length === 18) {
      let certificateNo: number = idCard.substring(16, 17);
      if (certificateNo % 2 === 0) {
        return "2";
      } else {
        return "1";
      }
    }
  }
}

/**
 * 根据身份证获取出生年月日
 * @param idCard
 */
function certificateNoInBirthday(idCard: any) {
  let birthdayStr = "";
  if (idCard) {
    // 提取出生日期
    let birthday = idCard.substring(6, 14);
    let year = birthday.substring(0, 4);
    let month = birthday.substring(4, 6);
    let day = birthday.substring(6, 8);
    birthdayStr = year + "-" + month + "-" + day;
  }
  return birthdayStr;
}

/**
 * 根据出生日期字符串 精确到几岁零几个月零几天零几小时
 * @param strBirthday
 * @returns
 */
function certificateNoInAge(strBirthday) {
  if (!strBirthday) {
    return null;
  }
  strBirthday = new Date(strBirthday);
  let yearBorn = strBirthday.getFullYear();
  let monthBorn = strBirthday.getMonth();
  let dayBorn = strBirthday.getDate();
  let nowDate = new Date();
  let year = nowDate.getFullYear();
  let month = nowDate.getMonth();
  let day = nowDate.getDate();
  let hour = nowDate.getHours();
  //间隔的年、月、日
  let yL = year - yearBorn;
  let mL = month - monthBorn;
  let dL = day - dayBorn;
  //统一的，计算间隔了XX年XX月XX天的方法。对日、月需要考虑借位的问题，年间隔一定>=0，所以不用考虑。这样一共有4种可能
  if (dL < 0) {
    dL = dL + getMonthDays(monthBorn + 1, yearBorn); //日不够减，向月借位。借哪个月的天数这里有点绕，看图解
    mL = mL - 1;
    if (mL < 0) {
      mL = mL + 12; //月向年借位
      yL = yL - 1;
    }
  } else {
    if (mL < 0) {
      mL = mL + 12; //月向年借位
      yL = yL - 1;
    }
  }

  //显示
  let yStr: number = 0;
  let mStr: number = 0;
  let dStr: number = 0;
  let hStr: number = 0;
  if (yL > 0) {
    // 岁
    yStr = yL;
  }
  if (mL > 0) {
    // 月
    mStr = mL;
  }
  if (dL > 0) {
    //天
    dStr = dL;
  }
  if (yL == 0 && mL == 0 && dL == 0) {
    //小时
    hStr = hour;
  }
  if (yL < 0 || (yL == 0 && mL < 0) || (yL == 0 && mL == 0 && dL < 0)) {
    return null;
  }
  return {
    yStr: yStr,
    mStr: mStr,
    dStr: dStr,
    hStr: hStr,
  };
}

//计算月的天数的函数
//31天的月: 1，3，5，7，8，10，12:2月较特殊:平年28天，闰年（被4整除）29天;30天的月:其余所有月
let getMonthDays = function (month, year) {
  let mDays;
  if (
    month == 1 ||
    month == 3 ||
    month == 5 ||
    month == 7 ||
    month == 8 ||
    month == 10 ||
    month == 12
  ) {
    mDays = 31;
  } else if (month == 2) {
    if (year % 4 == 0) {
      mDays = 29;
    } else {
      mDays = 28;
    }
  } else {
    mDays = 30;
  }
  return mDays;
};

// 回显数据字典
function selectDictLabel(datas, value) {
  if (value === undefined) {
    return "";
  }
  let actions: any[] = [];
  Object.keys(datas).some((key) => {
    if (datas[key].value == "" + value) {
      actions.push(datas[key].label);
      return true;
    }
  });
  if (actions.length === 0) {
    actions.push(value);
  }
  return actions.join("");
}

/** 设置全局table 表头背景色 */
function headerCellStyle() {
  return {"background-color": "#EEF0FF"};
}

function printPdfPublic(url, data) {
  return new Promise((resolve, reject) => {
    request({
      url: url,
      method: "post",
      responseType: "blob",
      data,
    })
      .then((res) => {
        const blob = new Blob([res.data], {
          // 关键代码，配置类型
          type: "application/pdf",
        });
        const {size} = blob;
        if (size > 0) {
          resolve(blob);
        } else {
          resolve(null);
        }
      })
      .catch((err) => {
        reject(err);
        console.error(err);
      });
  });
}

/**
 * 判断字符串是否为空后者 undefined ，真返回空
 * @param str
 */
function strIsUndefined(str) {
  return !str ? "" : str;
}

/** 回车下一个input获取焦点  需要给input设置 :tabindex属性*/
function changeFocus(_obj) {
  nextTick(() => {
    //@ts-ignore
    const currentIndex =
      //@ts-ignore
      Number(document.activeElement.getAttribute("tabindex")) || 0;
    const nextIndex = currentIndex + 1;
    const nextElement = document.querySelector(`[tabindex="${nextIndex}"]`);
    if (nextElement) {
      //@ts-ignore
      nextElement.focus();
    }
  });
}

/**
 * 日期增加天数
 * @param dayNumber 需要增加的天数
 * @param date 日期
 * @returns {Date}
 */
function addDay(dayNumber, date) {
  date = date ? date : new Date();
  let ms = dayNumber * (1000 * 60 * 60 * 24);
  return new Date(new Date(date).getTime() + ms);
}

/**
 * 求两日期差多少天
 * @param date1 开始时间
 * @param date2 结束时间
 * @returns {number}
 */
function getDaysDiff(date1, date2) {
  // 转换为毫秒数
  const oneDay = 24 * 60 * 60 * 1000;

  // 将日期字符串转换为 Date 对象
  const startDate = new Date(date1);
  const endDate = new Date(date2);

  // 计算两个日期之间的差值，再取绝对值
  // 返回计算结果
  //@ts-ignore
  return Math.abs((startDate - endDate) / oneDay);
}

/**
 * 字符串转数组
 * @param str 字符串
 * @param separatorTag 分隔符
 * @returns {*}
 */
function stringToArray(str, separatorTag) {
  if (typeof str == "string" && str.length > 0) {
    return str.split(separatorTag);
  }
  return "";
}

/** 患者信息框点击样式改变事件 */
function patientClickCssChange(index: number, patientList: any) {
  const cardRef = "patientCard-" + index;
  for (let i = 0; i < patientList.length; i++) {
    if (index === i) {
      const myDivParent = document.getElementById(cardRef) as HTMLElement;
      myDivParent.className = "box-card left-small-card patient-click-div";
      myDivParent.style.borderRadius = "5px";
    } else {
      const cardRef = "patientCard-" + i;
      const myDivParent = document.getElementById(cardRef) as HTMLElement;
      myDivParent.classList.remove("patient-click-div");
      myDivParent.style.borderRadius = "5px";
    }
  }
}

/**
 * 下拉框中tag css匹配
 * @param classInfo
 * @returns
 */
function mateStyle(classInfo) {
  let style = {
    backColor: "",
    color: ""
  };
  if (classInfo.listClass === 'primary') {
    style.backColor = "#ecf5ff";
    style.color = "#409eff"
  } else if (classInfo.listClass === 'success') {
    style.backColor = "#f0f9eb";
    style.color = "#95d475"
  } else if (classInfo.listClass === 'info') {
    style.backColor = "#ffffff";
    style.color = "#b1b3b8"
  } else if (classInfo.listClass === 'warning') {
    style.backColor = "#fdf6ec";
    style.color = "#eebe77"
  } else if (classInfo.listClass === 'danger') {
    style.backColor = "#fef0f0";
    style.color = "#ff0000"
  } else {
    style.backColor = "#ffffff";
    // style.color = "#ffffff"
  }
  return style;
}


/**
 * 获取数组中所有相同元素的下标
 * @param arr 原始数组
 * @param target 需要过滤的数据值
 * @param source 原始数组中需要判断的元素
 */
function getAllIndices(arr, target, source) {
  const indices = arr.map((item, index) => item[source] == target ? index : null)
    .filter((index) => index !== null);
  return indices;
}

/**
 * 数组去重
 * 思路：利用数组原型对象上的 filter 和 includes 方法
 * @param arr 需要去重的数组
 * @param t 根据 t 字段(指定)进行去重
 * @returns {*[]} 已去重后的数据
 */
function deduplicate(arr, t = "") {
  let newArr: any = []
  // 有指定字段
  if (t) {
    newArr = arr.filter(function (item: any) {
      return newArr.includes(item[t]) ? "" : newArr.push(item[t])
    })
  }
  // 无指定字段
  else {
    newArr = arr.filter(function (item: any) {
      return newArr.includes(item) ? "" : newArr.push(item)
    })
  }
  return newArr
}

/**
 * 日期时间选择框范围
 */
function shortcuts() {
  return [
    {
      text: '一周内',
      value: () => {
        const end = new Date()
        const start = new Date()
        start.setDate(start.getDate() - 7)
        return [start, end]
      },
    },
    {
      text: '一个月内',
      value: () => {
        const end = new Date()
        const start = new Date()
        start.setMonth(start.getMonth() - 1)
        return [start, end]
      },
    },
    {
      text: '三个月内',
      value: () => {
        const end = new Date()
        const start = new Date()
        start.setMonth(start.getMonth() - 3)
        return [start, end]
      },
    },
  ]
}

export {
  parseTime,
  tansParams,
  blobValidate,
  parseStrEmpty,
  getWeek,
  handleTree,
  getNormalPath,
  resetForm,
  addDateRange,
  certificateNoInSex,
  certificateNoInBirthday,
  certificateNoInAge,
  selectDictLabel,
  headerCellStyle,
  printPdfPublic,
  strIsUndefined,
  changeFocus,
  addDay,
  getDaysDiff,
  stringToArray,
  patientClickCssChange,
  mateStyle,
  getAllIndices,
  deduplicate,
  shortcuts
};
